import Data from "../object/Data"
import ObservableArray from "../observer/observable.array"
import { createMap } from "../observer/observable.map"
import AnimatedNumber from "../object/AnimatedNumber"
import sweepAlignmentEnum from "../enum/sweepAlignment.enum"
import Sweep from "../object/Sweep"
export default class SweepData extends Data {
  transitionActive: boolean
  sweepList: ObservableArray<Sweep>
  sweepMap: Record<string, Sweep>
  transition: { progress: AnimatedNumber; active: boolean; from: any; to: any }
  currentSweep: string
  constructor(e?: Record<string, Sweep>) {
    super()
    this.name = "sweeps"
    this.transitionActive = !1
    this.sweepList = new ObservableArray()
    this.sweepMap = {}
    if (e) {
      const t = Object.values(e).sort((e, t) => e.index - t.index)
      for (const e of t) (this.sweepMap[e.id] = e), this.sweepList.push(e)
    }
    this.transition = {
      progress: new AnimatedNumber(0),
      active: !1,
      from: void 0,
      to: void 0
    }
  }
  refresh(e) {
    for (const t in this.sweepMap) e[t] && this.sweepMap[t].refresh(e[t])
  }
  canTransition() {
    return !this.transition.active
  }
  get currentSweepIndex() {
    if (this.currentSweep) return this.sweepMap[this.currentSweep].index
    return null
  }
  get currentSweepObject() {
    if (this.currentSweep) return this.getSweep(this.currentSweep)
    return null
  }
  get currentAlignedSweepObject() {
    if (this.currentSweep && !this.isSweepUnaligned(this.currentSweep)) return this.getSweep(this.currentSweep)
    return null
  }
  makeSweepChangeSubscription(e) {
    return this.onPropertyChanged("currentSweep", e)
  }
  getSweep(e: string) {
    return this.sweepMap[e]
  }
  getSweepByIndex(e: number) {
    return this.sweepList.find(t => t.index === e)
  }
  getSweepByUuid(e: string) {
    return this.sweepList.find(t => t.uuid === e)
  }
  containsSweep(e: string) {
    return e in this.sweepMap
  }
  getFirstSweep() {
    let e = -1
    for (; ++e < this.sweepList.length; ) {
      const t = this.sweepList.get(e)
      if (t.enabled) return t
    }
  }
  getStartSweep(e) {
    const t = e && e.pano && e.pano.uuid ? this.getSweep(e.pano.uuid) : null
    return t && t.enabled ? t : this.getFirstSweep()
  }
  getClosestSweep(e, t) {
    let i = Number.MAX_VALUE
    let s = null
    this.iterate(r => {
      if (r.enabled && (!t || r.alignmentType === sweepAlignmentEnum.ALIGNED)) {
        const t = e.distanceTo(r.position)
        t < i && ((i = t), (s = r))
      }
    })
    return s
  }
  getFirstAlignedSweep() {
    let e = -1
    for (; ++e < this.sweepList.length; ) {
      const t = this.sweepList.get(e)
      if (t.enabled && t.alignmentType === sweepAlignmentEnum.ALIGNED) return t
    }
    return null
  }
  activateTransition(e, t) {
    this.transition.active = !0
    this.transition.from = t
    this.transition.to = e
    this.transitionActive = !0
  }
  deactivateTransition() {
    this.transition.active = !1
    this.transition.from = void 0
    this.transition.to = void 0
    this.transitionActive = !1
  }
  isSweepUnaligned(e: string) {
    if (!e) return !1
    const t = this.getSweep(e)
    return t && !t.isAligned()
  }
  isSweepAligned(e: string) {
    const t = this.getSweep(e)
    return t && t.isAligned()
  }
  isSweepDisabled(e = this.currentSweep) {
    if (!e) return !1
    const t = this.getSweep(e)
    return t && !t.enabled
  }
  *sweeps() {
    for (const e of this.sweepList) yield e
  }
  iterate(e: (v: Sweep, i?: number) => void) {
    this.sweepList.forEach((t, i) => {
      e(t, i)
    })
  }
  filter(e: (value: Sweep, index: number, array: Sweep[]) => boolean) {
    return this.sweepList.filter(e)
  }
  sortByScore(e: Function[], t: Function[], i: Sweep[] = this.sweepList.values()) {
    return i
      .filter(t => e.every(e => e(t)))
      .map(e => ({
        sweep: e,
        score: t.reduce((t, i) => t + i(e), 0)
      }))
      .sort((e, t) => t.score - e.score)
  }
  getSweepList() {
    return this.sweepList.values()
  }
  getSweepNeighbours(e: Sweep) {
    const t = []
    for (const i of e.neighbours) t.push(this.getSweep(i))
    return t as Sweep[]
  }
  getCollection() {
    return createMap(this.sweepMap)
  }
  getConnectedSweeps(e: string, t: Function) {
    const i = [e]
    const n = new Set()
    for (t = t || (e => !0); i.length; ) {
      const e = i.pop()
      const s = this.getSweep(e)
      n.add(e)
      for (const e of s.neighbours) {
        t(this.getSweep(e)) && !n.has(e) && i.push(e)
      }
    }
    return n
  }
  equals(e: SweepData) {
    if (
      this.sweepMap.length !== e.sweepMap.length ||
      this.currentSweep !== e.currentSweep ||
      this.transition.active !== e.transition.active ||
      this.transition.from !== e.transition.from ||
      this.transition.to !== e.transition.to
    )
      return !1
    for (const t in this.sweepMap) {
      if (!e.containsSweep(t)) return !1
      if (!this.sweepMap[t].equals(e.getSweep(t))) return !1
    }
    return !0
  }
}
